package org.leaf.green.b2b

import org.leaf.green.admin.RecordType
import org.springframework.transaction.annotation.*
import org.codehaus.groovy.grails.web.metaclass.BindDynamicMethod
import org.hibernate.FetchMode as FM
import org.hibernate.criterion.CriteriaSpecification

class StockInService {

    static transactional = true

    def updateInventory(StockIn stockIn) {
        log.info("[class=StockInService, method=updateInventory]")

        def success = false
        log.info("stockIn=${stockIn}")
        StockInDetail.findAllByStockIn(stockIn).each{
            log.info("stockInDetail=${it}")

            def inventory = Inventory.findByProductAndWarehouse(it.product, it.warehouse)
                
                if(inventory == null){
                    inventory = new Inventory(
                          warehouse : it.warehouse
                        , product: it.product
                        , unit : '斤'
                        , quantity : new BigDecimal(0)
                        , available : new BigDecimal(0)
                        , amount : new BigDecimal(0)
                    )
                }
                log.info("inventory.quantity=${inventory.quantity}")
                log.info("inventory.amount=${inventory.amount}")

                inventory.quantity += it.quantity
                inventory.available += it.quantity
                inventory.amount += it.amount

                log.info("inventory.quantity=${inventory.quantity}")
                log.info("inventory.amount=${inventory.amount}")

                inventory.save(flush:true)
            success = !inventory.hasErrors()
            log.info("success=${success}")
        }
        log.info("success=${success}")
        return success
    }

    def init(Object params){
        def purchase_or_pickplan_id = params['purchase.id']
            purchase_or_pickplan_id = purchase_or_pickplan_id ?: params['pickplan.id']

            log.info("purchase_or_pickplan_id=${purchase_or_pickplan_id}")
            log.info("purchase_or_pickplan_id=${purchase_or_pickplan_id.toLong()}")
        //new
        def stockinInstance = new StockIn()
            //set serialnumber
            stockinInstance.serialNumber = "${new Date().format('yyyyMMdd')}000"
            //set approved 
            stockinInstance.approved = false
        //get purchase
        def purchaseInstance = Purchase.withCriteria(uniqueResult:true){

            createAlias 'recordType', 'rt', CriteriaSpecification.LEFT_JOIN
            createAlias 'dealer', 'd', CriteriaSpecification.LEFT_JOIN

            projections{
                property("id")
                property("d.id")
                property("rt.serialNumber")
            }
            
            fetchMode "recordType", FM.JOIN
            fetchMode "dealer", FM.JOIN

            eq('id', purchase_or_pickplan_id.toLong())
        }
        log.info("purchaseInstance=${purchaseInstance}")
        //get record type
        def recordType_stockIn = RecordType.withCriteria(uniqueResult:true){
            projections{
                property("id")
                eq("serialNumber", purchaseInstance[2])
                eq("domain", "stockIn")
            }
        }
        log.info("recordType_stockIn=${recordType_stockIn}")
        //data binding
        BindDynamicMethod mybind = new BindDynamicMethod()
        def mymap = [
            'recordType.id' : recordType_stockIn, 
            'purchase.id': purchaseInstance[0],
            'dealer.id': purchaseInstance[1]
        ]
        def myargs =  [stockinInstance, mymap]
        mybind.invoke(stockinInstance, 'bind', (Object[]) myargs)
        
        //get purchase details
        def purchaseDetailInstanceList = PurchaseDetail.withCriteria(){

            createAlias 'dealer', 'd', CriteriaSpecification.LEFT_JOIN
            createAlias 'product', 'pro', CriteriaSpecification.LEFT_JOIN
            createAlias 'purchase', 'pur', CriteriaSpecification.LEFT_JOIN
            
            projections{
                property("id")
                property("d.id")
                property("pro.id")
                property("quantity")
                property("price")
                property("unit")
            }

            fetchMode "dealer", FM.JOIN
            fetchMode "product", FM.JOIN
            fetchMode "purchase", FM.JOIN

            eq("pur.id", purchase_or_pickplan_id.toLong())

            order("serialNumber", "asc") 
        }
        log.info("purchaseDetailInstanceList=${purchaseDetailInstanceList}")
        
        def begin_serialNumber = 0
        purchaseDetailInstanceList.each{
            begin_serialNumber += 1
            stockinInstance.addToDetails(
                new StockInDetail(
                      serialNumber : String.format('%03d', begin_serialNumber)
                    , purchaseDetail : it[0]
                    , dealer : it[1]
                    , product : it[2]
                    , warehouse : null
                    , life : new Date() + 3
                    , quantity : it[3]
                    , used : 0
                    , surplus : it[3]
                    , price : it[4]
                    , amount : it[3] * it[4]
                    , unit : it[5]
                    , isOver : false
                )
            )
             
        }

        return stockinInstance
    }

    //approval
    def approval(Long Id){
        def stockIn = StockIn.get(Id)
            stockIn.approved = true
 
            stockIn.save(flush:true)

        return !stockIn.hasErrors()
    }

    //record type
    @Transactional(readOnly = true)
    def type(Long Id) {
        def recordType = RecordType.withCriteria(uniqueResult:true){

            projections{   
                property("serialNumber")
            }
            
            eq("id", Id)
        }
        log.info("recordType=${recordType}")
        def type = "${recordType == '1' ? 'purchase' : 'pickplan'}"
        log.info("type=${type}")
        return type
    }
    
}
